﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscreteEventModel.Common {

    public class BitArray : IEnumerable<int> {

        private static List<int>[] _bitOffsets;

        static BitArray() {

            _bitOffsets = new List<int>[byte.MaxValue - byte.MinValue + 1];

            for(byte i = byte.MinValue; true; i++) {
                _bitOffsets[i] = new List<int>();
                for(int j = 0; j < 8; j++) {
                    if((i & (0x01 << j)) != 0) {
                        _bitOffsets[i].Add(j);
                    }
                }
                if(i == byte.MaxValue) {
                    break;
                }
            }
        }

        private byte[] _bytes;

        public BitArray(int length) {

            this._bytes = new byte[length / 8];
        }

        public int Length {
            get {
                return this._bytes.Length * 8;
            }
        }

        public bool this[int index] {
            get {
                return (this._bytes[index / 8] & (0x01 << (index % 8))) != 0;
            }
            set {
                if(value) {
                    this._bytes[index / 8] |= (byte)(0x01 << (index % 8));
                } else {
                    this._bytes[index / 8] &= (byte)(~(0x01 << (index % 8)));
                }
            }
        }

        public IEnumerable<int> BitIndexes {
            get {
                for(int byteIndex = 0; byteIndex < this._bytes.Length; byteIndex++) {
                    int baseIndex = byteIndex * 8;
                    foreach(int offset in _bitOffsets[this._bytes[byteIndex]]) {
                        yield return baseIndex + offset;
                    }
                }
            }
        }

        public IEnumerator<int> GetEnumerator() {
            return this.BitIndexes.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return this.BitIndexes.GetEnumerator();
        }
    }
}
